﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.DB.ExtensibleStorage;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.Controls;
using YArchitech.Revit;
using YJKArchUtils.Utils;
using YJKElementFinish.ColumnSurface.Controllers;
using YJKElementFinish.ColumnSurface.DataDefinition;
using YJKElementFinish.ColumnSurface.Managers;

namespace YJKRoomFixture.Kit
{
	internal class DrawDecorateEnt
	{
		public DrawDecorateEnt(ExternalCommandData cmdData, RoomDecorateFormInfo defInfoForm, List<Element> lstSelRooms)
		{
			this.m_cmdData = cmdData;
			this.m_defInfoForm = defInfoForm;
			this.m_lstSelRooms = lstSelRooms;
			this.m_doc = cmdData.Application.ActiveUIDocument.Document;
		}

		public static List<Element> GetMetopeType(Autodesk.Revit.DB.Document doc)
		{
			ICollection<Element> collection = new FilteredElementCollector(doc).OfClass(typeof(WallType)).ToElements();
			if (collection == null)
			{
				return null;
			}
			List<Element> list = collection.ToList<Element>();
			for (int i = 0; i < list.Count; i++)
			{
				WallType wallType = list[i] as WallType;
				Parameter parameter = wallType.get_Parameter(BuiltInParameter.FUNCTION_PARAM);
				bool flag = false;
				if (parameter != null)
				{
					flag = (parameter.AsInteger() == 0);
				}
				if (wallType.Kind != null || !flag)
				{
					list.RemoveAt(i);
					i--;
				}
			}
			return list;
		}

		public static List<Element> GetWallType(Autodesk.Revit.DB.Document doc)
		{
			ICollection<Element> collection = new FilteredElementCollector(doc).OfClass(typeof(WallType)).ToElements();
			if (collection == null)
			{
				return null;
			}
			List<Element> list = collection.ToList<Element>();
			for (int i = 0; i < list.Count; i++)
			{
				if ((list[i] as WallType).Kind != null)
				{
					list.RemoveAt(i);
					i--;
				}
			}
			return list;
		}

		public static List<Element> GetCeilingType(Autodesk.Revit.DB.Document doc)
		{
			bool bUseForCeiling = true;
			return DrawDecorateEnt.GetGroundTypeTol(doc, bUseForCeiling);
		}

		public static List<Element> GetGroundType(Autodesk.Revit.DB.Document doc)
		{
			bool bUseForCeiling = false;
			return DrawDecorateEnt.GetGroundTypeTol(doc, bUseForCeiling);
		}

		public static List<Element> GetGroundTypeTol(Autodesk.Revit.DB.Document doc, bool bUseForCeiling)
		{
			ICollection<Element> collection = new FilteredElementCollector(doc).OfClass(typeof(FloorType)).ToElements();
			if (collection == null)
			{
				return null;
			}
			List<Element> list = collection.ToList<Element>();
			for (int i = 0; i < list.Count; i++)
			{
				FloorType floorType = list[i] as FloorType;
				if (floorType.IsFoundationSlab)
				{
					list.RemoveAt(i);
					i--;
				}
				else
				{
					bool flag = DrawDecorateEnt.ReadFloorExData(floorType);
					if (bUseForCeiling)
					{
						if (!flag)
						{
							list.RemoveAt(i);
							i--;
						}
					}
					else if (flag)
					{
						list.RemoveAt(i);
						i--;
					}
				}
			}
			return list;
		}

		public static List<string> GetElementTypeNameList(List<Element> lstEntType)
		{
			List<string> list = new List<string>();
			foreach (Element element in lstEntType)
			{
				string name = element.Name;
				if (!name.IsEmpty<char>())
				{
					list.Add(name);
				}
			}
			return list;
		}

		public static List<string> GetListSkirtlineName(string strFileName, string strFamilyFilePath, Autodesk.Revit.DB.Document doc)
		{
			List<string> list = new List<string>();
			Transaction transaction = new Transaction(doc, "ImportFamily");
			transaction.Start();
			Document document = null;
			try
			{
				document = doc.Application.OpenDocumentFile(strFamilyFilePath);
				FamilyTypeSetIterator familyTypeSetIterator = document.FamilyManager.Types.ForwardIterator();
				familyTypeSetIterator.Reset();
				while (familyTypeSetIterator.MoveNext())
				{
					object obj = familyTypeSetIterator.Current;
					FamilyType familyType = obj as FamilyType;
					if (!(familyType.Name.TrimEnd(new char[]
					{
						' '
					}) == ""))
					{
						string item = strFileName + " " + familyType.Name;
						list.Add(item);
					}
				}
				if (list.Count == 0)
				{
					list.Add(strFileName);
				}
			}
			catch
			{
				transaction.RollBack();
				return list;
			}
			finally
			{
				if (document != null)
				{
					document.Close(false);
				}
			}
			transaction.RollBack();
			return list;
		}

		public static FamilySymbol GetSkirtlineFamilyTypeFromName(string strSelTypeName, string strFileName, string strFamilyFilePath, Autodesk.Revit.DB.Document doc)
		{
			Document document = null;
			string text = "";
			bool flag = false;
			try
			{
				document = doc.Application.OpenDocumentFile(strFamilyFilePath);
				FamilyTypeSetIterator familyTypeSetIterator = document.FamilyManager.Types.ForwardIterator();
				familyTypeSetIterator.Reset();
				while (familyTypeSetIterator.MoveNext())
				{
					object obj = familyTypeSetIterator.Current;
					FamilyType familyType = obj as FamilyType;
					string text2 = familyType.Name;
					text2 = text2.TrimEnd(new char[]
					{
						' '
					});
					if (text2 == strSelTypeName)
					{
						text = text2;
						flag = true;
						break;
					}
					if ((strFileName + " " + familyType.Name).TrimEnd(new char[]
					{
						' '
					}) == strSelTypeName)
					{
						text = familyType.Name;
						flag = true;
						break;
					}
				}
			}
			catch
			{
				return null;
			}
			finally
			{
				if (document != null)
				{
					document.Close(false);
				}
			}
			if (!flag)
			{
				return null;
			}
			try
			{
				FamilySymbol familySymbol = DrawDecorateEnt.GetFamilySymbol(strFileName, text, doc);
				if (familySymbol != null)
				{
					return familySymbol;
				}
				Family family = null;
				if (doc.LoadFamily(strFamilyFilePath, out family))
				{
					foreach (FamilySymbol familySymbol2 in family.GetSymbols())
					{
						if (familySymbol2.Name == text)
						{
							return familySymbol2;
						}
					}
				}
			}
			catch (Exception ex)
			{
				YJKMessageBox.Show(ex.Message);
				return null;
			}
			return null;
		}

		public static FamilySymbol GetFamilySymbol(string strFamilyName, string strSymbol, Autodesk.Revit.DB.Document doc)
		{
			List<Element> elementByClass = YJKElementFilter.GetElementByClass(typeof(FamilySymbol), doc);
			FamilySymbol result = null;
			if (elementByClass.Count <= 0)
			{
				return null;
			}
			foreach (Element element in elementByClass)
			{
				FamilySymbol familySymbol = element as FamilySymbol;
				if (familySymbol != null && familySymbol.Family.Name == strFamilyName && (familySymbol.Name == strSymbol || familySymbol.Name == strFamilyName))
				{
					result = familySymbol;
					break;
				}
			}
			return result;
		}

		public static bool IsValidSweepProfileCategory(string strFilePathName, Autodesk.Revit.DB.Document doc)
		{
			Transaction transaction = new Transaction(doc, "IsValidSweep");
			try
			{
				transaction.Start();
				Family family = null;
				if (doc.LoadFamily(strFilePathName, out family))
				{
					Category familyCategory = family.FamilyCategory;
					transaction.Commit();
					return familyCategory.Id.IntegerValue == -2003000;
				}
				transaction.Commit();
				return true;
			}
			catch (Exception ex)
			{
				YJKMessageBox.Show(ex.Message);
				transaction.RollBack();
			}
			return false;
		}

		public static WallType CreateWallTypeInner(string strWallTypeName, List<CompoundStructureLayer> lstLayers, Autodesk.Revit.DB.Document doc, bool bHasMessage = true)
		{
			List<Element> list = DrawDecorateEnt.GetMetopeType(doc);
			if (list == null || list.Count == 0)
			{
				list = DrawDecorateEnt.GetWallType(doc);
				if (list == null || list.Count == 0)
				{
					return null;
				}
			}
			WallType wallType = list[0] as WallType;
			List<CompoundStructureLayer> list2 = new List<CompoundStructureLayer>();
			foreach (CompoundStructureLayer compoundStructureLayer in lstLayers)
			{
				if (compoundStructureLayer != null)
				{
					list2.Add(compoundStructureLayer);
				}
			}
			Transaction transaction = new Transaction(doc, "CreateType");
			transaction.Start();
			WallType wallType2 = null;
			try
			{
				wallType2 = (wallType.Duplicate(strWallTypeName) as WallType);
				if (!WallTypeManager.UpdateCompoundStructure(wallType2, list2, doc))
				{
					transaction.RollBack();
					return null;
				}
				Parameter parameter = wallType2.GetParameter(BuiltInParameter.FUNCTION_PARAM);
				if (parameter != null)
				{
					parameter.Set(0);
				}
			}
			catch (Exception ex)
			{
				if (bHasMessage)
				{
					YJKMessageBox.Show(ex.Message);
				}
				transaction.RollBack();
				return null;
			}
			transaction.Commit();
			return wallType2;
		}

		public static FloorType CreateCeilingType(string strTypeName, List<CompoundStructureLayer> lstLayers, Autodesk.Revit.DB.Document doc, bool bHasMessage = true)
		{
			bool bIsCeiling = true;
			return DrawDecorateEnt.CreateGroundTypeTol(strTypeName, lstLayers, doc, bIsCeiling, bHasMessage);
		}

		public static FloorType CreateGroundType(string strTypeName, List<CompoundStructureLayer> lstLayers, Autodesk.Revit.DB.Document doc, bool bHasMessage = true)
		{
			bool bIsCeiling = false;
			return DrawDecorateEnt.CreateGroundTypeTol(strTypeName, lstLayers, doc, bIsCeiling, bHasMessage);
		}

		public static FloorType CreateGroundTypeTol(string strTypeName, List<CompoundStructureLayer> lstLayers, Autodesk.Revit.DB.Document doc, bool bIsCeiling, bool bHasMessage = true)
		{
			List<Element> groundType = DrawDecorateEnt.GetGroundType(doc);
			if (groundType == null || groundType.Count == 0)
			{
				return null;
			}
			FloorType floorType = groundType[0] as FloorType;
			List<CompoundStructureLayer> list = new List<CompoundStructureLayer>();
			foreach (CompoundStructureLayer compoundStructureLayer in lstLayers)
			{
				if (compoundStructureLayer != null)
				{
					list.Add(compoundStructureLayer);
				}
			}
			Transaction transaction = new Transaction(doc, "CreateType");
			transaction.Start();
			FloorType floorType2 = null;
			try
			{
				floorType2 = (floorType.Duplicate(strTypeName) as FloorType);
			}
			catch (Exception ex)
			{
				if (bHasMessage)
				{
					YJKMessageBox.Show(ex.Message);
				}
				transaction.RollBack();
				return null;
			}
			if (!WallTypeManager.UpdateCompoundStructure(floorType2, list, doc))
			{
				doc.Delete(floorType2.Id);
				transaction.RollBack();
				return null;
			}
			try
			{
				DrawDecorateEnt.WriteFloorExData(floorType2, bIsCeiling);
			}
			catch (Exception ex2)
			{
				if (bHasMessage)
				{
					YJKMessageBox.Show(ex2.Message);
				}
				doc.Delete(floorType2.Id);
				transaction.RollBack();
				return null;
			}
			transaction.Commit();
			return floorType2;
		}

		public bool DrawRoomDecorateMetopes(ref List<OffsetWallInfo> lstOffsetWallInfo, Autodesk.Revit.DB.ElementType elementType)
		{
			if (this.m_lstSelRooms.Count == 0 || elementType == null)
			{
				return false;
			}
			WallType wallType = elementType as WallType;
			List<ElementId> list = new List<ElementId>();
			try
			{
				List<Curve> lines = new List<Curve>();
				bool metopeIncludeColumn = this.m_defInfoForm.MetopeIncludeColumn;
				if (!new AddSurfaceLayersController(this.m_cmdData).SelectRoomProfile(ref lines, this.m_lstSelRooms, metopeIncludeColumn))
				{
					return false;
				}
				new RefCurveController(this.m_cmdData, list)
				{
					m_bNeedTransaction = false
				}.DrawLines(lines, ref list);
				new AddSurfaceLayersController(this.m_cmdData).AddSurfaceByRefCurve(ref lstOffsetWallInfo, wallType, list);
				RefCurveController.DeleteElementsWithoutTranslation(this.m_doc, list);
				if (lstOffsetWallInfo.Count == 0)
				{
					return false;
				}
				double num = AssistFunc.mmToFeet(this.m_defInfoForm.DefaultHighMetope);
				double num2 = AssistFunc.mmToFeet(this.m_defInfoForm.DefaultMetopeBottomOffset);
				double num3 = AssistFunc.mmToFeet(10.0);
				if (this.m_defInfoForm.MetopeTopToCeiling && this.m_defInfoForm.IncludeCeiling)
				{
					double num4 = AssistFunc.mmToFeet(this.m_defInfoForm.DefaultHighCeiling);
					if (num4 > num3)
					{
						num = num4;
					}
				}
				else
				{
					if (num < num3)
					{
						num = num3;
					}
					num += num2;
				}
				List<Element> list2 = new List<Element>();
				foreach (OffsetWallInfo offsetWallInfo in lstOffsetWallInfo)
				{
					List<Element> negativeWalls = offsetWallInfo.NegativeWalls;
					List<Element> positiveWalls = offsetWallInfo.PositiveWalls;
					if (negativeWalls != null && negativeWalls.Count > 0)
					{
						list2.AddRange(negativeWalls);
					}
					if (positiveWalls != null && positiveWalls.Count > 0)
					{
						list2.AddRange(positiveWalls);
					}
				}
				foreach (Element element in list2)
				{
					Wall wall = element as Wall;
					if (wall != null)
					{
						try
						{
							Parameter parameter = wall.GetParameter(BuiltInParameter.WALL_BASE_CONSTRAINT);
							if (parameter != null)
							{
								ElementId elementId = parameter.AsElementId();
								Parameter parameter2 = wall.GetParameter(BuiltInParameter.WALL_BASE_OFFSET);
								if (parameter2 != null)
								{
									parameter2.Set(num2);
									Parameter parameter3 = wall.GetParameter(BuiltInParameter.WALL_HEIGHT_TYPE);
									if (parameter3 != null)
									{
										parameter3.Set(elementId);
										Parameter parameter4 = wall.GetParameter(BuiltInParameter.WALL_TOP_OFFSET);
										if (parameter4 != null)
										{
											parameter4.Set(num);
										}
									}
								}
							}
						}
						catch
						{
							return false;
						}
					}
				}
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				RefCurveController.DeleteElementsWithoutTranslation(this.m_doc, list);
				return false;
			}
			return true;
		}

		public bool DrawRoomDecorateGrounds(ref List<Floor> lstFloors, Autodesk.Revit.DB.ElementType elementType)
		{
			bool bIsCeiling = false;
			return this.DrawRoomDecorateGroundsTol(ref lstFloors, elementType, bIsCeiling);
		}

		public bool DrawRoomDecorateCeilings(ref List<Floor> lstFloors, Autodesk.Revit.DB.ElementType elementType)
		{
			bool bIsCeiling = true;
			return this.DrawRoomDecorateGroundsTol(ref lstFloors, elementType, bIsCeiling);
		}

		public bool DrawRoomDecorateGroundsTol(ref List<Floor> lstFloors, Autodesk.Revit.DB.ElementType elementType, bool bIsCeiling)
		{
			if (this.m_lstSelRooms.Count == 0 || elementType == null)
			{
				return false;
			}
			new AddSurfaceLayersController(this.m_cmdData);
			foreach (Element element in this.m_lstSelRooms)
			{
				new List<Element>().Add(element);
				try
				{
					new List<Curve>();
					CurveArray roomInnerBoundaryCurves = DrawDecorateEnt.GetRoomInnerBoundaryCurves(element as Room);
					XYZ basisZ = XYZ.BasisZ;
					Level genLevel = this.m_doc.ActiveView.GenLevel;
					Floor floor = this.m_doc.Create.NewFloor(roomInnerBoundaryCurves, elementType as FloorType, genLevel, true, basisZ);
					double num2;
					if (bIsCeiling)
					{
						double num = floor.FloorType.GetParameter(BuiltInParameter.FLOOR_ATTR_DEFAULT_THICKNESS_PARAM).AsDouble();
						num2 = AssistFunc.mmToFeet(this.m_defInfoForm.DefaultHighCeiling) + num;
					}
					else
					{
						num2 = AssistFunc.mmToFeet(this.m_defInfoForm.DefaultHighGround);
					}
					Parameter parameter = floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM);
					if (parameter != null)
					{
						parameter.Set(num2);
					}
					lstFloors.Add(floor);
				}
				catch
				{
					YJKMessageBox.Show("创建楼板失败");
					return false;
				}
			}
			return true;
		}

		public bool DrawRoomDecorateSkirtlines(Autodesk.Revit.DB.ElementType elementType, Autodesk.Revit.DB.ElementType wallType)
		{
			if (elementType == null || wallType == null)
			{
				return false;
			}
			try
			{
				DrawSkirtline drawSkirtline = new DrawSkirtline(this.m_doc);
				bool bOnOutside = true;
				double dSkirtBottomHigh = 0.0;
				drawSkirtline.CreateSkirtlineWallType(wallType as WallType, elementType, bOnOutside, dSkirtBottomHigh);
			}
			catch (Exception ex)
			{
				YJKMessageBox.Show(ex.Message);
				return false;
			}
			return true;
		}

		public void GetRoomBoundarySegment(ref Dictionary<Element, bool> dictWallSide, Room room)
		{
			IList<IList<BoundarySegment>> boundarySegments = room.GetBoundarySegments(new SpatialElementBoundaryOptions());
			if (boundarySegments != null)
			{
				foreach (IList<BoundarySegment> list in boundarySegments)
				{
					foreach (BoundarySegment boundarySegment in list)
					{
						Curve curve = boundarySegment.GetCurve();
						Wall wall = boundarySegment.GetElement(this.m_doc) as Wall;
						if (!(curve == null) && wall != null)
						{
							Curve curve2 = (wall.Location as LocationCurve).Curve;
							dictWallSide.Add(wall, DrawDecorateEnt.IsTwoCurveCodirectional(curve, curve2));
						}
					}
				}
			}
		}

		public static bool IsTwoCurveCodirectional(Curve curve1, Curve curve2)
		{
			if (curve1.GetType() != curve2.GetType())
			{
				return false;
			}
			if (curve1.GetType() == typeof(Line))
			{
				XYZ xyz = curve1.GetEndPoint(0) - curve1.GetEndPoint(1);
				XYZ xyz2 = curve2.GetEndPoint(0) - curve2.GetEndPoint(1);
				XYZ pt = xyz.Normalize();
				xyz2 = xyz2.Normalize();
				return Geometry.IsEqual(pt, xyz2);
			}
			if (curve1.GetType() == typeof(Arc))
			{
				XYZ center = ((Arc)curve1).Center;
				XYZ center2 = ((Arc)curve2).Center;
				XYZ normal = ((Arc)curve1).Normal;
				XYZ normal2 = ((Arc)curve2).Normal;
				return Geometry.IsEqual(center, center2) && Geometry.IsEqual(normal, normal2);
			}
			return false;
		}

		private CurveArray CurveListToCurveArray(List<Curve> lstCurve)
		{
			CurveArray curveArray = new CurveArray();
			foreach (Curve curve in lstCurve)
			{
				curveArray.Append(curve);
			}
			return curveArray;
		}

		public static void WriteFloorExData(Autodesk.Revit.DB.ElementType floorType, bool bIsCeiling)
		{
			Guid guid = new Guid(DrawDecorateEnt.m_GuidFloorType);
			Schema schema = Schema.Lookup(guid);
			if (schema == null)
			{
				SchemaBuilder schemaBuilder = new SchemaBuilder(guid);
				schemaBuilder.SetSchemaName("FloorTypeXData");
				schemaBuilder.AddSimpleField(DrawDecorateEnt.m_strFloorTypeDefine, typeof(int));
				schema = schemaBuilder.Finish();
			}
			Entity entity = new Entity(schema);
			Field field = schema.GetField(DrawDecorateEnt.m_strFloorTypeDefine);
			entity.Set<int>(field, bIsCeiling ? 1 : 0);
			floorType.SetEntity(entity);
		}

		public static bool ReadFloorExData(Autodesk.Revit.DB.ElementType floorType)
		{
			try
			{
				Schema schema = Schema.Lookup(new Guid(DrawDecorateEnt.m_GuidFloorType));
				if (schema != null)
				{
					Entity entity = floorType.GetEntity(schema);
					if (entity != null && entity.Schema != null)
					{
						Field field = schema.GetField(DrawDecorateEnt.m_strFloorTypeDefine);
						return entity.Get<int>(field) == 1;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		public static CurveArray GetRoomInnerBoundaryCurves(Room room)
		{
			CurveArray curveArray = new CurveArray();
			try
			{
				foreach (IList<BoundarySegment> list in room.GetBoundarySegments(new SpatialElementBoundaryOptions()))
				{
					IEnumerator<BoundarySegment> enumerator2 = list.GetEnumerator();
					{
						while (enumerator2.MoveNext())
						{
							BoundarySegment segment = enumerator2.Current;
							curveArray.Append(segment.GetCurve());
						}
						break;
					}
				}
			}
			catch
			{
				return curveArray;
			}
			return curveArray;
		}

		private ExternalCommandData m_cmdData;

		private List<Element> m_lstSelRooms;

		private RoomDecorateFormInfo m_defInfoForm;

		private Document m_doc;

		private static string m_GuidFloorType = "6bf57f57-247d-40b9-b9d7-3f9718268890";

		private static string m_strFloorTypeDefine = "FloorTypeDefine";
	}
}
